{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 1. Object Oriented Programming\n", "\n", "In this exploration, we examine the idea of an object, and begin writing our first object-oriented programming study." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#Table of Contents\n", "* [1. Object Oriented Programming](#1.-Object-Oriented-Programming)\n", "\t* [1.1 Old Ball Code](#1.1-Old-Ball-Code)\n", "\t* [1.2 Bouncing Ball as an Object](#1.2-Bouncing-Ball-as-an-Object)\n", "\t* [1.3 Variations](#1.3-Variations)\n", "\t* [1.4 Collision Detection](#1.4-Collision-Detection)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.1 Old Ball Code" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This code is from the discussion on Bouncing Balls. We need to keep track of the ball's velocities in the `x` and `y` direction, keep track of where it is (`x`, `y`), and the global time. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " Sketch #1:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #1 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "float g = 9.8; \n", "\n", "float vx;\n", "float vy;\n", "\n", "int x;\n", "int y;\n", "\n", "float dt; \n", "float t;\n", "\n", "void setup() {\n", " size(200, 500);\n", " x = width/2;\n", " y = 50;\n", " dt = 0.1; \n", " t = 0;\n", " vx = 50.0;\n", " vy = 0.0;\n", "}\n", "\n", "void drawBall(int x, int y, int w, int h) {\n", " fill(255, 0, 0);\n", " ellipse(x, y, w, h);\n", "}\n", "\n", "void draw() {\n", " // gravity\n", " vy = vy + g * dt;\n", " \n", " dx = vx * dt; \n", " if (((x + dx) > width) || ((x + dx) < 0)) {\n", " vx = vx * -0.8;\n", " } else {\n", " x = x + dx;\n", " }\n", " \n", " dy = vy * dt;\n", " if (((y + dy) > height) || ((y + dy) < 0)) {\n", " vy = vy * -0.8;\n", " } else {\n", " y = y + dy;\n", " }\n", "\n", " drawBall(x, y, 10, 10);\n", " \n", " t = t + dt;\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What if we wanted to add more balls? We would need to add variables for vx, vy, x, y... for each ball!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.2 Bouncing Ball as an Object\n", "\n", "A better way is to let each ball keep track of its own properties. We do this by making a class definition, and storing each set of variables inside the Ball object.\n", "\n", "Here we will move all of the ball-specific variables \"into the Ball class\" and leave the others. We create an array of Balls, and bounce each one." ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " Sketch #33:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #33 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "// Globals:\n", "\n", "float g = 9.8; // gravity\n", "float dt = 0.1; // change in time\n", "float t = 0; // current time\n", "\n", "Ball [] balls; // the balls\n", "\n", "class Ball {\n", " int x;\n", " int y;\n", " int w;\n", " int h;\n", " float vx;\n", " float vy;\n", "\n", " // Jargon: the \"constructor\"\n", " Ball(int x, int y, int w, int h, float vx, float vy) {\n", " // Idea: \"this\" refers to the current ball\n", " this.x = x;\n", " this.y = y;\n", " this.w = w;\n", " this.h = h;\n", " this.vx = vx;\n", " this.vy = vy;\n", " }\n", " \n", " // Jargon: an object's function is called a \"method\"\n", " void moveYourself() {\n", " this.vy = this.vy + g * dt;\n", "\n", " dx = this.vx * dt; \n", " if (((this.x + dx) > width) || ((this.x + dx) < 0)) {\n", " this.vx = this.vx * -0.8;\n", " } else {\n", " this.x = this.x + dx;\n", " }\n", "\n", " dy = this.vy * dt;\n", " if (((this.y + dy) > height) || ((this.y + dy) < 0)) {\n", " this.vy = this.vy * -0.8;\n", " } else {\n", " this.y = this.y + dy;\n", " }\n", " }\n", " \n", " void drawYourself() {\n", " fill(255, 0, 0);\n", " ellipse(this.x, this.y, this.w, this.h);\n", " }\n", "}\n", "\n", "void setup() {\n", " size(200, 500);\n", " balls = new Ball[1];\n", " // Jargon: we create an \"instance\" of the Ball class:\n", " balls[0] = new Ball(width/2, 50, 10, 10, 50.0, 0.0);\n", " t = 0;\n", "}\n", "\n", "void draw() {\n", " balls[0].moveYourself();\n", " balls[0].drawYourself();\n", " \n", " t = t + dt;\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.3 Variations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cut and paste the above code and try some **variations**:\n", "\n", "1. More than one ball\n", "2. Add color to the balls\n", "3. Add a ball where you click the mouse" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " Sketch #41:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #41 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "// Globals:\n", "\n", "float g = 9.8; // gravity\n", "float dt = 0.1; // change in time\n", "float t = 0; // current time\n", "\n", "Ball [] balls; // the balls\n", "\n", "class Ball {\n", " int x;\n", " int y;\n", " int w;\n", " int h;\n", " float vx;\n", " float vy;\n", " color c;\n", "\n", " // Jargon: the \"constructor\"\n", " Ball(int x, int y, int w, int h, float vx, float vy) {\n", " // Idea: \"this\" refers to the current ball\n", " this.x = x;\n", " this.y = y;\n", " this.w = w;\n", " this.h = h;\n", " this.vx = vx;\n", " this.vy = vy;\n", " this.c = color(random(255), random(255), random(255));\n", " }\n", " \n", " // Jargon: an object's function is called a \"method\"\n", " void moveYourself() {\n", " this.vy = this.vy + g * dt;\n", "\n", " dx = this.vx * dt; \n", " if (((this.x + dx) > width) || ((this.x + dx) < 0)) {\n", " this.vx = this.vx * -0.8;\n", " } else {\n", " this.x = this.x + dx;\n", " }\n", "\n", " dy = this.vy * dt;\n", " if (((this.y + dy) > height) || ((this.y + dy) < 0)) {\n", " this.vy = this.vy * -0.8;\n", " } else {\n", " this.y = this.y + dy;\n", " }\n", " }\n", " \n", " void drawYourself() {\n", " fill(this.c);\n", " ellipse(this.x, this.y, this.w, this.h);\n", " }\n", "}\n", "\n", "void setup() {\n", " size(200, 500);\n", " balls = new Ball[1000];\n", " // Jargon: we create an \"instance\" of the Ball class:\n", " for (int i = 0; i < balls.length; i++) {\n", " balls[i] = new Ball(width * random(), height * random(), 10, 10, random(50) - 25, 0.0);\n", " }\n", " t = 0;\n", "}\n", "\n", "void draw() {\n", " background();\n", " for (int i = 0; i < balls.length; i++) {\n", " balls[i].moveYourself();\n", " balls[i].drawYourself();\n", " }\n", " t = t + dt;\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.4 Collision Detection\n", "\n", "It would be cool if the balls could detect when they run into each other, just like it detects when it hits a wall. To do that, we go through the other balls, and identify when they \"overlap\".\n", "\n", "Then, we simply swap their velocities." ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " Sketch #42:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #42 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "// Globals:\n", "\n", "float g = 9.8; // gravity\n", "float dt = 0.1; // change in time\n", "float t = 0; // current time\n", "\n", "Ball [] balls; // the balls\n", "\n", "float distance(float x1, float y1, float x2, float y2) {\n", " return sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)))\n", "}\n", "\n", "class Ball {\n", " color c;\n", " int x;\n", " int y;\n", " int w;\n", " int h;\n", " float vx;\n", " float vy;\n", "\n", " Ball(color c, int x, int y, int w, int h, int vx, int vy) {\n", " this.c = c;\n", " this.x = x;\n", " this.y = y;\n", " this.w = w;\n", " this.h = h;\n", " this.vx = vx;\n", " this.vy = vy;\n", " }\n", " \n", " void move() {\n", " this.vy = this.vy + g * dt; \n", " for (int i = 0; i < balls.length; i++) {\n", " if (balls[i] != this) {\n", " if (distance(this.x, this.y, balls[i].x, balls[i].y) < (this.w/2 + balls[i].w/2)) {\n", " temp = this.vx;\n", " this.vx = balls[i].vx;\n", " balls[i].vx = temp;\n", " temp = this.vy;\n", " this.vy = balls[i].vy;\n", " balls[i].vy = temp;\n", " break;\n", " }\n", " }\n", " }\n", " dx = this.vx * dt; \n", " dy = this.vy * dt;\n", " if (((this.x + dx) > width) || ((this.x + dx) < 0)) {\n", " this.vx = this.vx * -0.8;\n", " } else {\n", " this.x = this.x + dx;\n", " }\n", " if (((this.y + dy) > height) || ((this.y + dy) < 0)) {\n", " this.vy = this.vy * -0.8;\n", " } else {\n", " this.y = this.y + dy;\n", " }\n", " }\n", " \n", " void draw() {\n", " fill(this.c);\n", " ellipse(this.x, this.y, this.w, this.h);\n", " }\n", "}\n", "\n", "void setup() {\n", " size(200, 500);\n", " balls = new Ball[3];\n", " balls[0] = new Ball(color(255, 0, 0), width/2, 40, 10, 10, 50.0, 0.0);\n", " balls[1] = new Ball(color(0, 255, 0), width/2, 50, 10, 10, -40.0, 0.0);\n", " balls[2] = new Ball(color(0, 0, 255), width/2, 60, 10, 10, 0.0, 0.0);\n", " t = 0;\n", "}\n", "\n", "void draw() {\n", " balls[0].move();\n", " balls[0].draw();\n", " balls[1].move();\n", " balls[1].draw();\n", " balls[2].move();\n", " balls[2].draw();\n", " \n", " t = t + dt;\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Variations**:\n", "\n", "1. Create different kinds of balls (e.g., different shapes... just use your previous drawObject here)\n", "1. Make the Physics more realistic (e.g., add some loss of energy, randomness)\n", "2. Create them where you click the mouse.\n", "2. Take into account the balls' masses (e.g., like [this](http://gamedevelopment.tutsplus.com/tutorials/when-worlds-collide-simulating-circle-circle-collisions--gamedev-769)\n", "3. Have some things in the environment that don't move (gravity should not effect them, and they have no velocities)\n", "4. Have some locations that inject velocities (e.g., shoot objects into the air)" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " Sketch #48:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #48 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "// Globals:\n", "\n", "float g = 9.8; // gravity\n", "float dt = 0.1; // change in time\n", "float t = 0; // current time\n", "\n", "Ball [] balls; // the balls\n", "\n", "float distance(float x1, float y1, float x2, float y2) {\n", " return sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)))\n", "}\n", "\n", "class Ball {\n", " color c;\n", " int x;\n", " int y;\n", " int w;\n", " int h;\n", " float vx;\n", " float vy;\n", "\n", " Ball(color c, int x, int y, int w, int h, int vx, int vy) {\n", " this.c = c;\n", " this.x = x;\n", " this.y = y;\n", " this.w = w;\n", " this.h = h;\n", " this.vx = vx;\n", " this.vy = vy;\n", " }\n", " \n", " void move() {\n", " this.vy = this.vy + g * dt; \n", " for (int i = 0; i < balls.length; i++) {\n", " if (balls[i] != this) {\n", " if (distance(this.x, this.y, balls[i].x, balls[i].y) < (this.w/2 + balls[i].w/2)) {\n", " temp = this.vx;\n", " this.vx = balls[i].vx;\n", " balls[i].vx = temp;\n", " temp = this.vy;\n", " this.vy = balls[i].vy;\n", " balls[i].vy = temp;\n", " break;\n", " }\n", " }\n", " }\n", " dx = this.vx * dt; \n", " dy = this.vy * dt;\n", " if (((this.x + dx) > width) || ((this.x + dx) < 0)) {\n", " this.vx = this.vx * -0.8;\n", " } else {\n", " this.x = this.x + dx;\n", " }\n", " if (((this.y + dy) > height) || ((this.y + dy) < 0)) {\n", " this.vy = this.vy * -0.8;\n", " } else {\n", " this.y = this.y + dy;\n", " }\n", " }\n", " \n", " void draw() {\n", " fill(this.c);\n", " ellipse(this.x, this.y, this.w, this.h);\n", " }\n", "}\n", "\n", "void setup() {\n", " background();\n", " size(200, 500);\n", " balls = new Ball[100];\n", " for (int i = 0; i < balls.length; i++ ) {\n", " balls[i] = new Ball(color(random(255), random(255), random(255)), \n", " width * random(), height * random(), 10, 10, \n", " random(50.0) - 25, 0.0);\n", " }\n", " t = 0;\n", "}\n", "\n", "void draw() {\n", " for (int i = 0; i < balls.length; i++ ) {\n", " balls[i].move();\n", " balls[i].draw();\n", " } \n", " t = t + dt;\n", "}" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " Sketch #52:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #52 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "// Globals:\n", "\n", "float g = 9.8; // gravity\n", "float dt = 0.1; // change in time\n", "float t = 0; // current time\n", "\n", "Ball [] balls; // the balls\n", "\n", "float distance(float x1, float y1, float x2, float y2) {\n", " return sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)))\n", "}\n", "\n", "class Ball {\n", " color c;\n", " int x;\n", " int y;\n", " int w;\n", " int h;\n", " float vx;\n", " float vy;\n", "\n", " Ball(color c, int x, int y, int w, int h, int vx, int vy) {\n", " this.c = c;\n", " this.x = x;\n", " this.y = y;\n", " this.w = w;\n", " this.h = h;\n", " this.vx = vx;\n", " this.vy = vy;\n", " }\n", " \n", " void move() {\n", " this.vy = this.vy + g * dt; \n", " for (int i = 0; i < COUNT; i++) {\n", " if (balls[i] != this) {\n", " if (distance(this.x, this.y, balls[i].x, balls[i].y) < (this.w/2 + balls[i].w/2)) {\n", " temp = this.vx;\n", " this.vx = balls[i].vx;\n", " balls[i].vx = temp;\n", " temp = this.vy;\n", " this.vy = balls[i].vy;\n", " balls[i].vy = temp;\n", " break;\n", " }\n", " }\n", " }\n", " dx = this.vx * dt; \n", " dy = this.vy * dt;\n", " if (((this.x + dx) > width) || ((this.x + dx) < 0)) {\n", " this.vx = this.vx * -0.8;\n", " } else {\n", " this.x = this.x + dx;\n", " }\n", " if (((this.y + dy) > height) || ((this.y + dy) < 0)) {\n", " this.vy = this.vy * -0.8;\n", " } else {\n", " this.y = this.y + dy;\n", " }\n", " }\n", " \n", " void draw() {\n", " fill(this.c);\n", " ellipse(this.x, this.y, this.w, this.h);\n", " }\n", "}\n", "\n", "void setup() {\n", " size(200, 500);\n", " balls = new Ball[100];\n", " COUNT = 0;\n", " t = 0;\n", "}\n", "\n", "COUNT = 0;\n", "\n", "void mousePressed() {\n", " balls[COUNT] = new Ball(color(random(255), random(255), random(255)), \n", " mouseX, mouseY, 10, 10, random(50) - 25, 0);\n", " COUNT++;\n", "}\n", "\n", "void draw() {\n", " for (int i = 0; i < COUNT; i++) {\n", " balls[i].move();\n", " balls[i].draw();\n", " } \n", " t = t + dt;\n", "}" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Calysto Processing", "language": "processing", "name": "calysto_processing" }, "language_info": { "codemirror_mode": { "name": "text/x-java", "version": 2 }, "file_extension": ".java", "mimetype": "text/x-java", "name": "java" } }, "nbformat": 4, "nbformat_minor": 0 }